#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
THN DATA ABSTRACTION LAYER version 1

Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

This library is dual-licensed.
  + For commercial software, please obtain a commercial license from THN Solutions LLC.

  + For free software, this library is licensed under GPL version 3. A summary of GPLv3 is
    listed below. You should also find a copy of GPLv3 as file License_GPLv3.txt included
	with the source-code files.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 3 as published by
    the Free Software Foundation  of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
#region Using directives

using System;

#endregion

namespace Thn.Data
{
    /// <summary>
    /// A nested condition is a combination of two conditions.
    /// Supported operators: &, |
    ///     & : conditionA & conditionB => NestedCondition(A AND B)
    ///     | : conditionA & conditionB => NestedCondition(A OR B)
    /// </summary>
    [Serializable]
    public class NestedCondition: Condition
    {
        #region Fields
        Condition mLeft = null;
        /// <summary>
        /// Gets or Sets the left side condition
        /// </summary>
        public Condition Left
        {
            get { return mLeft; }
            set { mLeft = value; }
        }

        Condition mRight = null;
        /// <summary>
        /// Gets or Sets the right side condition
        /// </summary>
        public Condition Right
        {
            get { return mRight; }
            set { mRight = value; }
        }

        CombinationType mCombination = CombinationType.And;
        /// <summary>
        /// Gets or Sets the combination type 
        /// </summary>
        public CombinationType Combination
        {
            get { return mCombination; }
            set { mCombination = value; }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// Create a (...) AND (...) nested condition
        /// </summary>
        public NestedCondition(Condition LeftCondition, Condition RightCondition)
        {
            mLeft = LeftCondition;
            mRight = RightCondition;
        }

		/// <summary>
		/// Create a new instance
		/// </summary>
        public NestedCondition(Condition LeftCondition, Condition RightCondition, CombinationType Combination)
        {
            mLeft = LeftCondition;
            mRight = RightCondition;
            mCombination = Combination;
        }
        #endregion

        #region Operators overload
		/// <summary>
		/// Create a nested condition based on 2 nested conditions with operation AND
		/// </summary>
        public static NestedCondition operator &(NestedCondition c1, NestedCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
			else return new NestedCondition(c1, c2, CombinationType.And);
        }

		/// <summary>
		/// Create a nested condition based on 2 nested conditions with operation OR
		/// </summary>
        public static NestedCondition operator |(NestedCondition c1, NestedCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
			else return new NestedCondition(c1, c2, CombinationType.Or);
        }

		/// <summary>
		/// Equality
		/// </summary>
        public static bool operator ==(NestedCondition c1, NestedCondition c2)
        {
            return c1.Equals(c2);
        }

		/// <summary>
		/// Inequality
		/// </summary>
        public static bool operator !=(NestedCondition c1, NestedCondition c2)
        {
            return c1.Equals(c2);
        }
        #endregion

        #region Equals
		/// <summary>
		/// Equality test
		/// </summary>
        public override bool Equals(object obj)
        {
            bool equal = false;

            if (obj is NestedCondition)
            {
                NestedCondition nc = (NestedCondition)obj;
                equal = nc.mLeft.Equals(mLeft) && nc.mRight.Equals(mRight) && nc.mCombination.Equals(mCombination);
            }

            return equal;
        }

        /// <summary>
        /// Gets ID of this object
        /// </summary>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        #endregion

        #region ToString()
        /// <summary>
        /// Converts to string
        /// </summary>
        public override string ToString()
        {
            if (mCombination == CombinationType.And)
                return " (" + mLeft.ToString() + " AND " + mRight.ToString() + ") ";
            else
                return " (" + mLeft.ToString() + " OR " + mRight.ToString() + ") ";
        }

        #endregion
    }

	/// <summary>
	/// Type of merging conditions
	/// </summary>
    public enum CombinationType
    {
        /// <summary>
        /// Both conditions must be met
        /// </summary>
        And,

        /// <summary>
        /// Either conditions can be met
        /// </summary>
        Or
    }
}
